home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume89
/
editors
/
stevie36.3
< prev
next >
Wrap
Internet Message Format
|
1989-05-12
|
59KB
Path: xanth!nic.MR.NET!umn-d-ub!rutgers!apple!oliveb!sun!swap!page
From: page%swap@Sun.COM (Bob Page)
Newsgroups: comp.sources.amiga
Subject: v89i132: stevie - vi editor clone v3.6, Part03/06
Message-ID: <104419@sun.Eng.Sun.COM>
Date: 12 May 89 03:06:43 GMT
Sender: news@sun.Eng.Sun.COM
Lines: 2778
Approved: page@sun.com
Submitted-by: grwalter@watmath.waterloo.edu (Fred Walter)
Posting-number: Volume 89, Issue 132
Archive-name: editors/stevie36.3
# This is a shell archive.
# Remove anything above and including the cut line.
# Then run the rest of the file through 'sh'.
# Unpacked files will be owned by you and have default permissions.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# shar: SHell ARchive
# Run the following text through 'sh' to create:
# makefile.amiga.lattice
# makefile.bsd
# makefile.dos
# makefile.mwc
# makefile.os2
# makefile.tos
# makefile.usg
# mark.c
# misccmds.c
# mk.c
# normal.c
# This is archive 3 of a 6-part kit.
# This archive created: Thu May 11 19:41:26 1989
echo "extracting makefile.amiga.lattice"
sed 's/^X//' << \SHAR_EOF > makefile.amiga.lattice
X#
X# Makefile for Lattice C 5.0 on Amiga
X#
X
X.c.o:
X lc $(CFLAGS) $<
X
X#CFLAGS = -cu -ma -DAMIGA
XCFLAGS = -cu -ma -O -DAMIGA
XLINKFLAGS = NODEBUG
XLIBS = lib:lc.lib
X
XMACH= amiga.o
X
XOBJ1= main.o edit.o linefunc.o normal.o cmdline.o charset.o
XOBJ2= format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o
XOBJ3= mk.o regexp.o regsub.o version.o
XOBJ4= s_io.o mark.o screen.o fileio.o param.o
X
XOBJ= $(OBJ1) $(OBJ2) $(OBJ3) $(OBJ4) $(MACH)
X
Xall: stevie
X say "done all"
X
Xstevie: $(OBJ) Makefile
X BLINK TO stevie FROM lib:cres.o $(OBJ) LIBRARY $(LIBS) $(LINKFLAGS)
X
Xclean:
X delete $(OBJ1)
X delete $(OBJ2)
X delete $(OBJ3)
X delete $(OBJ4)
X delete $(MACH)
X delete stevie
SHAR_EOF
echo "extracting makefile.bsd"
sed 's/^X//' << \SHAR_EOF > makefile.bsd
X#
X# Makefile for BSD 4.3 UNIX
X#
X
XCFLAGS = -O -DBSD
X#CFLAGS = -pg -g -DBSD
XLINTFLAGS = -DBSD
X
XMACHOBJ= bsd.o
XMACHSRC= bsd.c
X
XSRC= main.c edit.c linefunc.c normal.c cmdline.c charset.c \
X misccmds.c help.c dec.c inc.c search.c alloc.c \
X format_l.c mk.c regexp.c regsub.c version.c \
X s_io.c mark.c screen.c fileio.c param.c $(MACHSRC)
X
XOBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \
X misccmds.o help.o dec.o inc.o search.o alloc.o \
X format_l.o mk.o regexp.o regsub.o version.o \
X s_io.o mark.o screen.o fileio.o param.o $(MACHOBJ)
X
Xall : stevie
X
Xstevie : $(OBJ)
X $(CC) $(OBJ) $(CFLAGS) -o stevie
X
Xlint:
X lint $(LINTFLAGS) $(SRC)
X
Xclean :
X rm -f *.out *.o core stevie *.BAK
SHAR_EOF
echo "extracting makefile.dos"
sed 's/^X//' << \SHAR_EOF > makefile.dos
X#
X# Makefile for DOS
X#
X# This makefile is set up for Microsoft C 5.1
X#
X
X#
X# Compact model lets us edit large files, but keep small model code
X#
XMODEL= /AC
XCFLAGS = $(MODEL)
X
XMACH= dos.obj
X
XOBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
X mk.obj format_l.obj regexp.obj regsub.obj version.obj \
X misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
X s_io.obj mark.obj screen.obj fileio.obj param.obj $(MACH)
X
Xall: stevie.exe
X
Xmain.obj: main.c
X cl -c $(CFLAGS) main.c
X
Xformat_l.obj: format_l.c
X cl -c $(CFLAGS) format_l.c
X
Xmk.obj: mk.c
X cl -c $(CFLAGS) mk.c
X
Xregexp.obj: regexp.c
X cl -c $(CFLAGS) regexp.c
X
Xregsub.obj: regsub.c
X cl -c $(CFLAGS) regsub.c
X
Xversion.obj: version.c
X cl -c $(CFLAGS) version.c
X
Xalloc.obj : alloc.c
X cl -c $(CFLAGS) alloc.c
X
Xedit.obj : edit.c
X cl -c $(CFLAGS) edit.c
X
Xs_io.obj : s_io.c
X cl -c $(CFLAGS) s_io.c
X
Xlinefunc.obj : linefunc.c
X cl -c $(CFLAGS) linefunc.c
X
Xnormal.obj : normal.c
X cl -c $(CFLAGS) normal.c
X
Xcmdline.obj : cmdline.c
X cl -c $(CFLAGS) cmdline.c
X
Xcharset.obj : charset.c
X cl -c $(CFLAGS) charset.c
X
Xmisccmds.obj : misccmds.c
X cl -c $(CFLAGS) misccmds.c
X
Xhelp.obj : help.c
X cl -c $(CFLAGS) help.c
X
Xdec.obj : dec.c
X cl -c $(CFLAGS) dec.c
X
Xinc.obj : inc.c
X cl -c $(CFLAGS) inc.c
X
Xsearch.obj : search.c
X cl -c $(CFLAGS) search.c
X
Xmark.obj : mark.c
X cl -c $(CFLAGS) mark.c
X
Xscreen.obj : screen.c
X cl -c $(CFLAGS) screen.c
X
Xfileio.obj : fileio.c
X cl -c $(CFLAGS) fileio.c
X
Xparam.obj : param.c
X cl -c $(CFLAGS) param.c
X
Xdos.obj : dos.c
X cl -c $(CFLAGS) dos.c
X
Xstevie.exe : $(OBJ)
X cl $(MODEL) *.obj c:\lib\setargv.obj -o stevie.exe /F 6000 -link /NOE
SHAR_EOF
echo "extracting makefile.mwc"
sed 's/^X//' << \SHAR_EOF > makefile.mwc
X#
X#
X#
X# Makefile for Mark Williams C
X#
XCFLAGS = -O -VPEEP
XLDFLAGS = -s -x -v
XLINKER=ld
X
XOBJ1= main.o edit.o linefunc.o normal.o cmdline.o charset.o \
X format_l.o misccmds.o help.o dec.o inc.o
XOBJ2= alloc.o search.o mk.o regexp.o regsub.o version.o s_io.o \
X mark.o screen.o fileio.o param.o tos.o
X
XSRC= main.c edit.c linefunc.c normal.c cmdline.c charset.c \
X format_l.c misccmds.c help.c dec.c inc.c search.c alloc.c \
X mk.c regexp.c regsub.c version.c \
X s_io.c mark.c screen.c fileio.c param.c \
X tos.c
X
X
Xall : stevie.ttp
X
Xstevie.a: $(OBJ1) $(OBJ2)
X ar rv stevie.a $(OBJ1)
X ar rv stevie.a $(OBJ2)
X
Xstevie.ttp: stevie.a
X cc stevie.a $(LIBS) -o stevie.ttp
SHAR_EOF
echo "extracting makefile.os2"
sed 's/^X//' << \SHAR_EOF > makefile.os2
X#
X# Makefile for OS/2
X#
X# The make command with OS/2 is really stupid.
X#
X
X#
X# Compact model lets us edit large files, but keep small model code
X#
XMODEL= -AC
XCFLAGS = $(MODEL) -I..\regexp -J
X
XMACH= os2.obj
X
XOBJ= main.obj edit.obj linefunc.obj normal.obj cmdline.obj charset.obj \
X mk.obj format_l.obj regexp.obj regsub.obj version.obj \
X misccmds.obj help.obj dec.obj inc.obj search.obj alloc.obj \
X s_io.obj mark.obj screen.obj fileio.obj param.obj $(MACH)
X
Xall: stevie.exe
X
Xmain.obj: main.c
X cl -c $(CFLAGS) main.c
X
Xformat_l.obj: format_l.c
X cl -c $(CFLAGS) format_l.c
X
Xmk.obj: mk.c
X cl -c $(CFLAGS) mk.c
X
Xregexp.obj: regexp.c
X cl -c $(CFLAGS) regexp.c
X
Xregsub.obj: regsub.c
X cl -c $(CFLAGS) regsub.c
X
Xversion.obj: version.c
X cl -c $(CFLAGS) version.c
X
Xalloc.obj : alloc.c
X cl -c $(CFLAGS) alloc.c
X
Xedit.obj : edit.c
X cl -c $(CFLAGS) edit.c
X
Xs_io.obj : s_io.c
X cl -c $(CFLAGS) s_io.c
X
Xlinefunc.obj : linefunc.c
X cl -c $(CFLAGS) linefunc.c
X
Xnormal.obj : normal.c
X cl -c $(CFLAGS) normal.c
X
Xcmdline.obj : cmdline.c
X cl -c $(CFLAGS) cmdline.c
X
Xcharset.obj : charset.c
X cl -c $(CFLAGS) charset.c
X
Xmisccmds.obj : misccmds.c
X cl -c $(CFLAGS) misccmds.c
X
Xhelp.obj : help.c
X cl -c $(CFLAGS) help.c
X
Xdec.obj : dec.c
X cl -c $(CFLAGS) dec.c
X
Xinc.obj : inc.c
X cl -c $(CFLAGS) inc.c
X
Xsearch.obj : search.c
X cl -c $(CFLAGS) search.c
X
Xmark.obj : mark.c
X cl -c $(CFLAGS) mark.c
X
Xscreen.obj : screen.c
X cl -c $(CFLAGS) screen.c
X
Xfileio.obj : fileio.c
X cl -c $(CFLAGS) fileio.c
X
Xparam.obj : param.c
X cl -c $(CFLAGS) param.c
X
Xos2.obj : os2.c
X cl -c $(CFLAGS) os2.c
X
Xstevie.exe : $(OBJ)
X cl $(MODEL) *.obj $(LIBS) -o stevie.exe /Lo # use protected mode lib.
X copy stevie.exe rstevie.exe
X bind rstevie.exe \lib\api.lib \lib\doscalls.lib
SHAR_EOF
echo "extracting makefile.tos"
sed 's/^X//' << \SHAR_EOF > makefile.tos
X#
X# Makefile for the Atari ST - Megamax C compiler
X#
X
XCFLAGS = -DMEGAMAX
X
X# Megamax rule
X.c.o:
X mmcc $(CFLAGS) $<
X mmimp $*.o
X mmlib rv vi.lib $*.o
X
XMACH= tos.o
X
XOBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \
X format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o \
X mk.o regexp.o regsub.o version.o \
X s_io.o mark.o screen.o fileio.o param.o $(MACH)
X
Xall : stevie.ttp
X
Xstevie.ttp : $(OBJ)
X $(LINKER) vi.lib $(LIBS) -o stevie.ttp
X
Xclean :
X $(RM) $(OBJ) vi.lib
SHAR_EOF
echo "extracting makefile.usg"
sed 's/^X//' << \SHAR_EOF > makefile.usg
X#
X# Makefile for UNIX (System V)
X#
X
XCFLAGS = -O -DUNIX
X
XMACH= unix.o
X
XOBJ= main.o edit.o linefunc.o normal.o cmdline.o charset.o \
X format_l.o misccmds.o help.o dec.o inc.o search.o alloc.o \
X mk.o regexp.o regsub.o version.o \
X s_io.o mark.o screen.o fileio.o param.o $(MACH)
X
Xall : stevie
X
Xstevie : $(OBJ)
X $(CC) $(OBJ) $(LIBS) -o stevie
X
Xclean :
X rm $(OBJ)
SHAR_EOF
echo "extracting mark.c"
sed 's/^X//' << \SHAR_EOF > mark.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
X#ifdef MEGAMAX
Xoverlay "mark"
X#endif
X
X/*
X * This file contains routines to maintain and manipulate marks.
X */
X
X#define NMARKS 10 /* max. # of marks that can be saved */
X
Xstruct mark {
X char name;
X LPtr pos;
X};
X
Xstatic struct mark mlist[NMARKS];
Xstatic struct mark pcmark; /* previous context mark */
Xstatic bool_t pcvalid = FALSE;/* true if pcmark is valid */
X
X/*
X * setmark(c) - set mark 'c' at current cursor position
X *
X * Returns TRUE on success, FALSE if no room for mark or bad name given.
X */
Xbool_t
Xsetmark(c)
X char c;
X{
X int i;
X
X if (!isalpha(c))
X return FALSE;
X
X /*
X * If there is already a mark of this name, then just use the existing
X * mark entry.
X */
X for (i = 0; i < NMARKS; i++) {
X if (mlist[i].name == c) {
X mlist[i].pos = *Curschar;
X return TRUE;
X }
X }
X
X /*
X * There wasn't a mark of the given name, so find a free slot
X */
X for (i = 0; i < NMARKS; i++) {
X if (mlist[i].name == NUL) { /* got a free one */
X mlist[i].name = c;
X mlist[i].pos = *Curschar;
X return TRUE;
X }
X }
X return FALSE;
X}
X
X/*
X * setpcmark() - set the previous context mark to the current position
X */
Xvoid
Xsetpcmark()
X{
X pcmark.pos = *Curschar;
X pcvalid = TRUE;
X}
X
X/*
X * getmark(c) - find mark for char 'c'
X *
X * Return pointer to LPtr or NULL if no such mark.
X */
XLPtr *
Xgetmark(c)
X char c;
X{
X int i;
X
X if (c == '\'' || c == '`') /* previous context mark */
X return pcvalid ? &(pcmark.pos) : (LPtr *) NULL;
X
X for (i = 0; i < NMARKS; i++) {
X if (mlist[i].name == c)
X return &(mlist[i].pos);
X }
X return (LPtr *) NULL;
X}
X
X/*
X * clrall() - clear all marks
X *
X * Used mainly when trashing the entire buffer during ":e" type commands
X */
Xvoid
Xclrall()
X{
X int i;
X
X for (i = 0; i < NMARKS; i++)
X mlist[i].name = NUL;
X pcvalid = FALSE;
X}
X
X/*
X * clrmark(line) - clear any marks for 'line'
X *
X * Used any time a line is deleted so we don't have marks pointing to
X * non-existent lines.
X */
Xvoid
Xclrmark(line)
X LINE *line;
X{
X int i;
X
X for (i = 0; i < NMARKS; i++) {
X if (mlist[i].pos.linep == line)
X mlist[i].name = NUL;
X }
X if (pcvalid && (pcmark.pos.linep == line))
X pcvalid = FALSE;
X}
SHAR_EOF
echo "extracting misccmds.c"
sed 's/^X//' << \SHAR_EOF > misccmds.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xextern int did_ai;
X
X/*
X * OpenForward
X *
X * Add a blank line below the current line.
X */
X
Xbool_t
XOpenForward(can_ai)
X int can_ai;
X{
X LINE *l;
X LPtr *next;
X char *s; /* string to be moved to new line, if any */
X int newindex = 0; /* index of the cursor on the new
X * line */
X
X /*
X * If we're in insert mode, we need to move the remainder of the current
X * line onto the new line. Otherwise the new line is left blank.
X */
X if (State == INSERT)
X s = &Curschar->linep->s[Curschar->index];
X else
X s = "";
X
X if ((next = nextline(Curschar)) == NULL) /* open on last line */
X next = Fileend;
X
X /*
X * By asking for as much space as the prior line had we make sure that
X * we'll have enough space for any auto-indenting.
X */
X l = newline(strlen(Curschar->linep->s) + SLOP);
X if (l == NULL) {
X emsg("out of memory");
X beep();
X sleep(2);
X return (FALSE);
X }
X if (can_ai && P(P_AI)) {
X char *p;
X
X /*
X * Copy prior line, and truncate after white space
X */
X strcpy(l->s, Curschar->linep->s);
X
X for (p = l->s; *p == ' ' || *p == TAB; p++);
X *p = NUL;
X newindex = p - l->s;
X AppendToInsbuff(l->s);
X if (*s != NUL)
X strcat(l->s, s);
X
X /*
X * If we just did an auto-indent, then we didn't type anything on the
X * prior line, and it should be truncated.
X */
X if (did_ai)
X Curschar->linep->s[0] = NUL;
X
X did_ai = TRUE;
X } else if (*s != NUL) {
X strcpy(l->s, s); /* copy string to new line */
X }
X if (State == INSERT) /* truncate current line at cursor */
X *s = NUL;
X
X Curschar->linep->next = l; /* link neighbors to new line */
X next->linep->prev = l;
X
X l->prev = Curschar->linep; /* link new line to neighbors */
X l->next = next->linep;
X
X if (next == Fileend) { /* new line at end */
X l->num = Curschar->linep->num + LINEINC;
X } else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */
X renum();
X } else { /* stick it in the middle */
X long lnum;
X
X lnum = (l->prev->num + l->next->num) / 2;
X l->num = lnum;
X }
X
X *Curschar = *nextline(Curschar); /* cursor moves down */
X Curschar->index = newindex;
X
X S_NOT_VALID;
X CHANGED;
X
X return (TRUE);
X}
X
X/*
X * OpenBackward
X *
X * Add a blank line above the current line.
X */
X
Xbool_t
XOpenBackward(can_ai)
X int can_ai;
X{
X LINE *l;
X LINE *prev;
X int newindex = 0; /* index of the cursor on the new
X * line */
X
X prev = Curschar->linep->prev;
X
X l = newline(strlen(Curschar->linep->s) + SLOP);
X if (l == NULL) {
X emsg("out of memory");
X beep();
X sleep(2);
X return (FALSE);
X }
X Curschar->linep->prev = l; /* link neighbors to new line */
X prev->next = l;
X
X l->next = Curschar->linep; /* link new line to neighbors */
X l->prev = prev;
X
X if (can_ai && P(P_AI)) {
X char *p;
X
X /*
X * Copy current line, and truncate after white space
X */
X strcpy(l->s, Curschar->linep->s);
X
X for (p = l->s; *p == ' ' || *p == TAB; p++);
X *p = NUL;
X newindex = p - l->s;
X AppendToInsbuff(l->s);
X
X did_ai = TRUE;
X }
X Curschar->linep = Curschar->linep->prev;
X Curschar->index = newindex;
X
X if (prev == Filetop->linep) { /* new start of file */
X Filemem->linep = l;
X renum();
X } else if ((l->prev->num) + 1 == l->next->num) { /* no gap, renumber */
X renum();
X } else { /* stick it in the middle */
X long lnum;
X
X lnum = (l->prev->num + l->next->num) / 2;
X l->num = lnum;
X }
X
X S_NOT_VALID;
X CHANGED;
X
X return (TRUE);
X}
X
Xint
Xcntllines(pbegin, pend)
X LPtr *pbegin, *pend;
X{
X register LINE *lp;
X register int lnum = 1;
X
X for (lp = pbegin->linep; lp != pend->linep; lp = lp->next)
X lnum++;
X
X return (lnum);
X}
X
X/*
X * plines(s) - return the number of physical screen lines taken by the
X * line pointed to by 's'
X */
X
Xint
Xplines(s)
X register char *s;
X{
X register int col = 0;
X
X if (*s == NUL) /* empty line */
X return 1;
X
X for (; *s != NUL; s++) {
X if (*s == TAB && !P(P_LS))
X col += P(P_TS) - (col % P(P_TS));
X else
X col += chars[*s].ch_size;
X }
X
X /*
X * If list mode is on, then the '$' at the end of the line takes up one
X * extra column.
X */
X if (P(P_LS))
X col += 1;
X
X /*
X * If 'number' mode is on, add another 8.
X */
X if (P(P_NU))
X col += 8;
X
X return ((col + (Columns - 1)) / Columns);
X}
X
Xvoid
Xfileinfo()
X{
X long l1, l2;
X char buf[MAX_COLUMNS + 1];
X
X if (bufempty()) {
X msg("Buffer Empty");
X return;
X }
X l1 = cntllines(Filemem, Curschar);
X l2 = cntllines(Filemem, Fileend) - 1;
X sprintf(buf, "\"%s\"%s line %ld of %ld -- %ld %% --",
X (Filename != NULL) ? Filename : "No File",
X Changed ? " [Modified]" : "",
X l1, l2, (l1 * 100) / l2);
X msg(buf);
X}
X
X/*
X * gotoline(n) - return a pointer to line 'n'
X *
X * Returns a pointer to the last line of the file if n is zero, or beyond the
X * end of the file.
X */
XLPtr *
Xgotoline(n)
X int n;
X{
X static LPtr l;
X
X l.index = 0;
X
X if (n == 0)
X l = *prevline(Fileend);
X else {
X LPtr *p;
X
X for (l = *Filemem; --n > 0; l = *p)
X if ((p = nextline(&l)) == NULL)
X break;
X }
X return &l;
X}
X
Xvoid
Xinschar(c)
X char c;
X{
X register char *p;
X register char *pend;
X
X /* make room for the new char. */
X if (!canincrease(1))
X return;
X
X p = &Curschar->linep->s[strlen(Curschar->linep->s) + 1];
X pend = &Curschar->linep->s[Curschar->index];
X
X for (; p > pend; p--)
X *p = *(p - 1);
X
X *p = c;
X
X if (RedrawingDisabled) {
X Curschar->index++;
X return;
X }
X /*
X * If we're in insert mode and showmatch mode is set, then check for
X * right parens and braces. If there isn't a match, then beep. If there
X * is a match AND it's on the screen, then flash to it briefly. If it
X * isn't on the screen, don't do anything.
X */
X if (P(P_SM) && State == INSERT && (c == ')' || c == '}' || c == ']')) {
X LPtr *lpos, csave;
X
X if ((lpos = showmatch()) == NULL) /* no match, so beep */
X beep();
X else if (LINEOF(lpos) >= LINEOF(Topchar)) {
X /* show the new char first */
X s_refresh(VALID_TO_CURSCHAR);
X csave = *Curschar;
X *Curschar = *lpos; /* move to matching char */
X cursupdate(UPDATE_CURSOR);
X windgoto(Cursrow, Curscol);
X delay(); /* brief pause */
X *Curschar = csave; /* restore cursor position */
X cursupdate(UPDATE_ALL);
X }
X }
X inc(Curschar);
X
X CHANGED;
X}
X
Xvoid
Xinsstr(s)
X register char *s;
X{
X register char *p;
X register char *pend;
X register int n = strlen(s);
X
X /* Move everything in the file over to make */
X /* room for the new string. */
X if (!canincrease(n))
X return;
X
X p = &Curschar->linep->s[strlen(Curschar->linep->s) + n];
X pend = &Curschar->linep->s[Curschar->index];
X
X for (; p > pend; p--)
X *p = *(p - n);
X
X for (; n > 0; n--) {
X *p++ = *s++;
X Curschar->index++;
X }
X CHANGED;
X}
X
Xbool_t
Xdelchar(fixpos, undo)
X bool_t fixpos; /* if TRUE fix the cursor position when done */
X bool_t undo; /* if TRUE put char deleted into Undo buffer */
X{
X int i;
X
X /* Check for degenerate case; there's nothing in the file. */
X if (bufempty())
X return FALSE;
X
X if (lineempty(Curschar)) /* can't do anything */
X return FALSE;
X
X if (undo)
X AppendToUndobuff(mkstr(gchar(Curschar)));
X
X /* Delete the char. at Curschar by shifting everything in the line down. */
X for (i = Curschar->index + 1; i < Curschar->linep->size; i++)
X Curschar->linep->s[i - 1] = Curschar->linep->s[i];
X
X /*
X * If we just took off the last character of a non-blank line, we don't
X * want to end up positioned at the newline.
X */
X if (fixpos) {
X if (gchar(Curschar) == NUL && Curschar->index > 0 && State != INSERT)
X Curschar->index--;
X }
X CHANGED;
X return TRUE;
X}
X
Xvoid
Xdelline(nlines)
X int nlines;
X{
X register LINE *p;
X register LINE *q;
X
X while (nlines-- > 0) {
X
X if (bufempty()) /* nothing to delete */
X break;
X
X if (buf1line()) { /* just clear the line */
X Curschar->linep->s[0] = NUL;
X Curschar->index = 0;
X break;
X }
X p = Curschar->linep->prev;
X q = Curschar->linep->next;
X
X if (p == Filetop->linep) { /* first line of file so... */
X Filemem->linep = q; /* adjust start of file */
X Topchar->linep = q; /* and screen */
X }
X p->next = q;
X q->prev = p;
X
X clrmark(Curschar->linep); /* clear marks for the line */
X
X /*
X * If deleting the top line on the screen, adjust Topchar
X */
X if (Topchar->linep == Curschar->linep)
X Topchar->linep = q;
X
X free(Curschar->linep->s);
X free((char *) (Curschar->linep));
X
X Curschar->linep = q;
X Curschar->index = 0; /* is this right? */
X
X S_NOT_VALID;
X CHANGED;
X
X /* If we delete the last line in the file, back up */
X if (Curschar->linep == Fileend->linep) {
X Curschar->linep = Curschar->linep->prev;
X /* and don't try to delete any more lines */
X break;
X }
X }
X}
SHAR_EOF
echo "extracting mk.c"
sed 's/^X//' << \SHAR_EOF > mk.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X#include "stevie.h"
X
Xchar *
Xmkline(n)
X int n;
X{
X static char lbuf[9];
X int i = 6;
X
X strcpy(lbuf, " ");
X
X lbuf[i--] = (char) ((n % 10) + '0');
X n /= 10;
X if (n != 0) {
X lbuf[i--] = (char) ((n % 10) + '0');
X n /= 10;
X }
X if (n != 0) {
X lbuf[i--] = (char) ((n % 10) + '0');
X n /= 10;
X }
X if (n != 0) {
X lbuf[i--] = (char) ((n % 10) + '0');
X n /= 10;
X }
X if (n != 0)
X lbuf[i] = (char) ((n % 10) + '0');
X
X return lbuf;
X}
X
Xchar *
Xmkstr(c)
X char c;
X{
X static char s[2];
X
X s[0] = c;
X s[1] = NUL;
X
X return s;
X}
SHAR_EOF
echo "extracting normal.c"
sed 's/^X//' << \SHAR_EOF > normal.c
X/*
X * STEVIE - Simply Try this Editor for VI Enthusiasts
X *
X * Code Contributions By : Tim Thompson twitch!tjt
X * Tony Andrews onecom!wldrdg!tony
X * G. R. (Fred) Walter watmath!watcgl!grwalter
X */
X
X/*
X * This file contains the main routine for processing characters in command
X * mode as well as routines for handling the operators.
X */
X
X#include "stevie.h"
X
Xstatic void
Xdoshift(), dodelete(), doput(), dochange();
Xstatic void
X startinsert();
Xstatic bool_t
X dojoin();
Xstatic bool_t
X doyank();
X
X/*
X * Macro evaluates true if char 'c' is a valid identifier character
X */
X#define IDCHAR(c) (isalpha(c) || isdigit(c) || (c) == '_')
X
X/*
X * Operators
X */
X#define NOP 0 /* no pending operation */
X#define DELETE 1
X#define YANK 2
X#define CHANGE 3
X#define LSHIFT 4
X#define RSHIFT 5
X
X#define CLEAROP (operator = NOP)/* clear any pending operator */
X
Xstatic int operator = NOP; /* current pending operator */
X
X/*
X * When a cursor motion command is made, it is marked as being a character or
X * line oriented motion. Then, if an operator is in effect, the operation
X * becomes character or line oriented accordingly.
X *
X * Character motions are marked as being inclusive or not. Most char. motions
X * are inclusive, but some (e.g. 'w') are not.
X *
X * Generally speaking, every command in normal() should either clear any pending
X * operator (with CLEAROP), or set the motion type variable.
X */
X
X/*
X * Motion types
X */
X#define MBAD (-1) /* 'bad' motion type marks unusable yank buf */
X#define MCHAR 0
X#define MLINE 1
X
Xstatic int mtype; /* type of the current cursor motion */
Xstatic bool_t mincl; /* true if char motion is inclusive */
Xstatic int ybtype = MBAD;
Xstatic int ybcrossline = FALSE;
X
Xstatic LPtr startop; /* cursor pos. at start of operator */
X
X/*
X * Operators can have counts either before the operator, or between the
X * operator and the following cursor motion as in:
X *
X * d3w or 3dw
X *
X * If a count is given before the operator, it is saved in opnum. If normal() is
X * called with a pending operator, the count in opnum (if present) overrides
X * any count that came later.
X */
Xstatic int opnum = 0;
X
X#define DEFAULT1(x) (((x) == 0) ? 1 : (x))
X
X/*
X * normal
X *
X * Execute a command in normal mode.
X */
X
Xvoid
Xnormal(c)
X char c;
X{
X char *p;
X int n;
X int nn;
X bool_t flag = FALSE;
X int type = 0; /* used in some operations to modify type */
X int dir = FORWARD; /* search direction */
X char nchar = NUL;
X bool_t finish_op;
X LPtr temp_Curschar;
X
X last_command = NUL;
X /*
X * If there is an operator pending, then the command we take this time
X * will terminate it. Finish_op tells us to finish the operation before
X * returning this time (unless the operation was cancelled).
X */
X finish_op = (operator != NOP);
X
X /*
X * If we're in the middle of an operator AND we had a count before the
X * operator, then that count overrides the current value of Prenum. What
X * this means effectively, is that commands like "3dw" get turned into
X * "d3w" which makes things fall into place pretty neatly.
X */
X if (finish_op) {
X if (opnum != 0)
X Prenum = opnum;
X } else
X opnum = 0;
X
X switch (c) {
X
X case K_HELP:
X CLEAROP;
X if (help())
X s_clear();
X break;
X
X case CTRL('L'):
X CLEAROP;
X s_clear();
X break;
X
X case CTRL('D'):
X CLEAROP;
X if (Prenum)
X P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
X scrollup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
X onedown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
X break;
X
X case CTRL('U'):
X CLEAROP;
X if (Prenum)
X P(P_SS) = (Prenum > Rows - 1) ? Rows - 1 : Prenum;
X scrolldown((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
X oneup((P(P_SS) < Rows) ? P(P_SS) : Rows - 1);
X break;
X
X case CTRL('F'):
X CLEAROP;
X if (nextline(Topchar) == NULL) {
X beep();
X break;
X }
X Prenum = DEFAULT1(Prenum);
X while (Prenum > 0) {
X *Curschar = *prevline(Botchar);
X *Topchar = *Curschar;
X Topchar->index = 0;
X Update_Botchar();
X Prenum--;
X }
X beginline(TRUE);
X s_clear();
X break;
X
X case CTRL('B'):
X CLEAROP;
X if (prevline(Topchar) == NULL) {
X beep();
X break;
X }
X Prenum = DEFAULT1(Prenum);
X while (Prenum > 0) {
X *Curschar = *Topchar;
X n = Rows - 1;
X {
X LPtr *lp = Curschar;
X int l = 0;
X
X while ((l < n) && (lp != NULL)) {
X l += plines(lp->linep->s);
X *Topchar = *lp;
X lp = prevline(lp);
X }
X }
X Topchar->index = 0;
X Prenum--;
X }
X beginline(TRUE);
X s_clear();
X break;
X
X case CTRL('E'):
X CLEAROP;
X scrollup(DEFAULT1(Prenum));
X if (LINEOF(Curschar) < LINEOF(Topchar))
X Curschar->linep = Topchar->linep;
X break;
X
X case CTRL('Y'):
X CLEAROP;
X scrolldown(DEFAULT1(Prenum));
X Update_Botchar();
X if (LINEOF(Curschar) >= LINEOF(Botchar)) {
X LPtr *lp;
X
X lp = prevline(Botchar);
X if (lp == NULL)
X lp = Topchar;
X Curschar->linep = lp->linep;
X }
X break;
X
X case 'z':
X CLEAROP;
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X switch (vgetc()) {
X case NL: /* put Curschar at top of screen */
X case CR:
X *Topchar = *Curschar;
X Topchar->index = 0;
X break;
X
X case '.': /* put Curschar in middle of screen */
X n = Rows / 2;
X goto dozcmd;
X
X case '-': /* put Curschar at bottom of screen */
X n = Rows - 1;
X /* FALLTHROUGH */
X
X dozcmd:
X {
X register LPtr *lp = Curschar;
X register int l = 0;
X
X while ((l < n) && (lp != NULL)) {
X l += plines(lp->linep->s);
X *Topchar = *lp;
X lp = prevline(lp);
X }
X }
X Topchar->index = 0;
X break;
X
X default:
X beep();
X }
X break;
X
X case CTRL('G'):
X CLEAROP;
X fileinfo();
X break;
X
X case 'G':
X mtype = MLINE;
X *Curschar = *gotoline(Prenum);
X if (!UndoInProgress) {
X beginline(TRUE);
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X }
X break;
X
X case 'H':
X mtype = MLINE;
X *Curschar = *Topchar;
X for (n = Prenum; n && onedown(1); n--);
X beginline(TRUE);
X break;
X
X case 'M':
X mtype = MLINE;
X *Curschar = *Topchar;
X for (n = 0; n < Rows / 2 && onedown(1); n++);
X beginline(TRUE);
X break;
X
X case 'L':
X mtype = MLINE;
X *Curschar = *prevline(Botchar);
X for (n = Prenum; n && oneup(1); n--);
X beginline(TRUE);
X break;
X
X case 'l':
X case K_RARROW:
X case ' ':
X mtype = MCHAR;
X mincl = FALSE;
X n = DEFAULT1(Prenum);
X while (n--) {
X if (!oneright()) {
X if (operator != DELETE && operator != CHANGE) {
X beep();
X } else {
X if (lineempty(Curschar)) {
X CLEAROP;
X beep();
X } else {
X mincl = TRUE;
X }
X }
X break;
X }
X }
X set_want_col = TRUE;
X break;
X
X case 'h':
X case K_LARROW:
X case CTRL('H'):
X mtype = MCHAR;
X mincl = FALSE;
X Prenum = DEFAULT1(Prenum);
X n = Prenum;
X while (n--) {
X if (!oneleft()) {
X if (operator != DELETE && operator != CHANGE) {
X beep();
X } else if (Prenum == 1) {
X CLEAROP;
X beep();
X }
X break;
X }
X }
X set_want_col = TRUE;
X break;
X
X case '-':
X flag = TRUE;
X /* FALLTHROUGH */
X
X case 'k':
X case K_UARROW:
X case CTRL('P'):
X mtype = MLINE;
X if (!oneup(DEFAULT1(Prenum))) {
X CLEAROP;
X beep();
X } else if (flag)
X beginline(TRUE);
X break;
X
X case '+':
X case CR:
X case NL:
X flag = TRUE;
X /* FALLTHROUGH */
X
X case 'j':
X case K_DARROW:
X case CTRL('N'):
X mtype = MLINE;
X if (!onedown(DEFAULT1(Prenum))) {
X CLEAROP;
X beep();
X } else if (flag)
X beginline(TRUE);
X break;
X
X /*
X * This is a strange motion command that helps make operators more
X * logical. It is actually implemented, but not documented in the
X * real 'vi'. This motion command actually refers to "the current
X * line". Commands like "dd" and "yy" are really an alternate form of
X * "d_" and "y_". It does accept a count, so "d3_" works to delete 3
X * lines.
X */
X case '_':
Xlineop:
X mtype = MLINE;
X if (!onedown(DEFAULT1(Prenum) - 1)) {
X CLEAROP;
X beep();
X } else
X beginline(TRUE);
X break;
X
X case '|':
X mtype = MCHAR;
X mincl = TRUE;
X beginline(FALSE);
X if (Prenum > 0)
X coladvance(Curschar, Prenum - 1);
X Curswant = Prenum - 1;
X break;
X
X case CTRL(']'): /* :ta to current identifier */
X CLEAROP;
X {
X char ch;
X LPtr save;
X
X save = *Curschar;
X /*
X * First back up to start of identifier. This doesn't match the
X * real vi but I like it a little better and it shouldn't bother
X * anyone.
X */
X ch = gchar(Curschar);
X while (IDCHAR(ch)) {
X if (!oneleft())
X break;
X ch = gchar(Curschar);
X }
X if (!IDCHAR(ch))
X oneright();
X
X stuffReadbuff(":ta ");
X /*
X * Now grab the chars in the identifier
X */
X ch = gchar(Curschar);
X while (IDCHAR(ch)) {
X stuffReadbuff(mkstr(ch));
X if (!oneright())
X break;
X ch = gchar(Curschar);
X }
X stuffReadbuff("\n");
X
X *Curschar = save; /* restore, in case of error */
X }
X break;
X
X case '%':
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X mtype = MCHAR;
X mincl = TRUE;
X {
X LPtr *pos;
X
X if ((pos = showmatch()) == NULL) {
X CLEAROP;
X beep();
X } else {
X setpcmark();
X *Curschar = *pos;
X set_want_col = TRUE;
X }
X }
X break;
X
X /*
X * Word Motions
X */
X
X case 'B':
X type = 1;
X /* FALLTHROUGH */
X
X case 'b':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0; n--) {
X LPtr *pos;
X
X if ((Curschar->linep->prev == Filetop->linep)
X && (Curschar->index == 0)) {
X CLEAROP;
X beep();
X break;
X }
X pos = bck_word(Curschar, type);
X if (pos == NULL) {
X CLEAROP;
X beep();
X *Curschar = *gotoline(1); /* goto top of file */
X } else
X *Curschar = *pos;
X }
X break;
X
X case 'W':
X type = 1;
X /* FALLTHROUGH */
X
X case 'w':
X /*
X * This is a little strange. To match what the real vi does, we
X * effectively map 'cw' to 'ce', and 'cW' to 'cE'. This seems
X * impolite at first, but it's really more what we mean when we say
X * 'cw'.
X */
X if (operator == CHANGE)
X goto do_e_cmd;
X
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0; n--) {
X LPtr *pos;
X
X if ((pos = fwd_word(Curschar, type)) == NULL) {
X CLEAROP;
X beep();
X break;
X } else
X *Curschar = *pos;
X }
X break;
X
X case 'E':
X type = 1;
X /* FALLTHROUGH */
X
X case 'e':
Xdo_e_cmd:
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X for (n = DEFAULT1(Prenum); n > 0; n--) {
X LPtr *pos;
X
X if ((pos = end_word(Curschar, type)) == NULL) {
X CLEAROP;
X beep();
X break;
X } else
X *Curschar = *pos;
X }
X break;
X
X case '$':
X mtype = MCHAR;
X mincl = TRUE;
X while (oneright());
X Curswant = 999; /* so we stay at the end */
X break;
X
X case '^':
X flag = TRUE;
X /* FALLTHROUGH */
X
X case '0':
X mtype = MCHAR;
X mincl = TRUE;
X beginline(flag);
X break;
X
X case 'A':
X set_want_col = TRUE;
X while (oneright());
X ResetBuffers();
X AppendToRedobuff("A");
X goto doAPPENDcmd;
X
X case 'a':
X ResetBuffers();
X AppendToRedobuff("a");
X
XdoAPPENDcmd:
X CLEAROP;
X /* Works just like an 'i'nsert on the next character. */
X n = RowNumber(Curschar);
X AppendPositionToUndoUndobuff(Curschar->index, n);
X AppendToUndoUndobuff("a");
X
X if (!lineempty(Curschar))
X inc(Curschar);
X
X n = RowNumber(Curschar);
X AppendPositionToUndobuff(Curschar->index, n);
X
X startinsert(FALSE);
X break;
X
X case 'I':
X beginline(TRUE);
X ResetBuffers();
X AppendToRedobuff("I");
X goto doINSERTcmd;
X /* FALLTHROUGH */
X
X case 'i':
X case K_INSERT:
X ResetBuffers();
X AppendToRedobuff("i");
X
XdoINSERTcmd:
X CLEAROP;
X
X n = RowNumber(Curschar);
X AppendPositionToUndobuff(Curschar->index, n);
X AppendPositionToUndoUndobuff(Curschar->index, n);
X AppendToUndoUndobuff("i");
X
X startinsert(FALSE);
X break;
X
X case 'o':
X CLEAROP;
X ResetBuffers();
X
X n = RowNumber(Curschar);
X AppendToRedobuff("o");
X AppendPositionToUndobuff(Curschar->index, n);
X AppendPositionToUndoUndobuff(Curschar->index, n);
X AppendToUndoUndobuff("o");
X
X if (OpenForward(!RedrawingDisabled))
X startinsert(TRUE);
X
X last_command = 'o';
X break;
X
X case 'O':
X CLEAROP;
X ResetBuffers();
X
X n = RowNumber(Curschar);
X AppendToRedobuff("O");
X AppendPositionToUndobuff(Curschar->index, n);
X AppendPositionToUndoUndobuff(Curschar->index, n);
X AppendToUndoUndobuff("O");
X
X if (OpenBackward(!RedrawingDisabled))
X startinsert(TRUE);
X
X last_command = 'O';
X break;
X
X case 'd':
X if (operator == DELETE) /* handle 'dd' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = DELETE;
X break;
X
X /*
X * Some convenient abbreviations...
X */
X
X case 'x':
X if (Prenum)
X stuffnumReadbuff(Prenum);
X stuffReadbuff("dl");
X break;
X
X case 'X':
X if (Prenum)
X stuffnumReadbuff(Prenum);
X stuffReadbuff("dh");
X break;
X
X case 'D':
X stuffReadbuff("d$");
X break;
X
X case 'Y':
X if (Prenum)
X stuffnumReadbuff(Prenum);
X stuffReadbuff("yy");
X break;
X
X case 'C':
X stuffReadbuff("c$");
X break;
X
X case 'c':
X if (operator == CHANGE) { /* handle 'cc' */
X CLEAROP;
X stuffReadbuff("0c$");
X break;
X }
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = CHANGE;
X break;
X
X case 'y':
X if (operator == YANK) /* handle 'yy' */
X goto lineop;
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar;
X operator = YANK;
X break;
X
X case ENABLE_REDRAWING:
X RedrawingDisabled = FALSE;
X S_NOT_VALID;
X break;
X
X case 'p':
X if (Yankbuffptr != NULL) {
X doput(FORWARD);
X
X stuffReadbuff(ENABLE_REDRAWING_STR);
X RedrawingDisabled = TRUE;
X } else
X beep();
X break;
X
X case 'P':
X if (Yankbuffptr != NULL) {
X doput(BACKWARD);
X
X stuffReadbuff(ENABLE_REDRAWING_STR);
X RedrawingDisabled = TRUE;
X } else
X beep();
X break;
X
X case '>':
X if (operator == RSHIFT) /* handle >> */
X goto lineop;
X if (operator == LSHIFT) {
X CLEAROP;
X beep();
X break;
X }
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar; /* save current position */
X operator = RSHIFT;
X break;
X
X case '<':
X if (operator == LSHIFT) /* handle << */
X goto lineop;
X if (operator == RSHIFT) {
X CLEAROP;
X beep();
X break;
X }
X if (Prenum != 0)
X opnum = Prenum;
X startop = *Curschar; /* save current position */
X operator = LSHIFT;
X break;
X
X case 's': /* substitute characters */
X if (Prenum)
X stuffnumReadbuff(Prenum);
X stuffReadbuff("cl");
X break;
X
X case '?':
X case '/':
X case ':':
X CLEAROP;
X readcmdline(c, (char *) NULL);
X break;
X
X case 'n':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X if (!repsearch(0)) {
X CLEAROP;
X beep();
X }
X break;
X
X case 'N':
X mtype = MCHAR;
X mincl = FALSE;
X set_want_col = TRUE;
X if (!repsearch(1)) {
X CLEAROP;
X beep();
X }
X break;
X
X /*
X * Character searches
X */
X case 'T':
X dir = BACKWARD;
X /* FALLTHROUGH */
X
X case 't':
X type = 1;
X goto docsearch;
X
X case 'F':
X dir = BACKWARD;
X /* FALLTHROUGH */
X
X case 'f':
Xdocsearch:
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X if ((nchar = vgetc()) == ESC) /* search char */
X break;
X if (!searchc(nchar, dir, type)) {
X CLEAROP;
X beep();
X }
X break;
X
X case ',':
X flag = 1;
X /* FALLTHROUGH */
X
X case ';':
X mtype = MCHAR;
X mincl = TRUE;
X set_want_col = TRUE;
X if (!crepsearch(flag)) {
X CLEAROP;
X beep();
X }
X break;
X
X /*
X * Function searches
X */
X
X case '[':
X dir = BACKWARD;
X /* FALLTHROUGH */
X
X case ']':
X mtype = MLINE;
X set_want_col = TRUE;
X if (vgetc() != c) {
X CLEAROP;
X beep();
X break;
X }
X if (!findfunc(dir)) {
X CLEAROP;
X beep();
X }
X break;
X
X /*
X * Marks
X */
X
X case 'm':
X CLEAROP;
X if (!setmark(vgetc()))
X beep();
X break;
X
X case '\'':
X flag = TRUE;
X /* FALLTHROUGH */
X
X case '`':
X S_CHECK_TOPCHAR_AND_BOTCHAR;
X {
X LPtr mtmp;
X LPtr *mark = getmark(vgetc());
X
X if (mark == NULL) {
X CLEAROP;
X beep();
X } else {
X mtmp = *mark;
X setpcmark();
X *Curschar = mtmp;
X if (flag)
X beginline(TRUE);
X }
X mtype = flag ? MLINE : MCHAR;
X mincl = TRUE; /* ignored if not MCHAR */
X set_want_col = TRUE;
X }
X break;
X
X case 'r':
X CLEAROP;
X if (lineempty(Curschar)) { /* Nothing to replace */
X beep();
X break;
X }
X if ((nchar = vgetc()) == ESC)
X break;
X
X Prenum = DEFAULT1(Prenum);
X n = strlen(Curschar->linep->s) - Curschar->index;
X if (n < Prenum) {
X beep();
X break;
X }
X ResetBuffers();
X
X nn = RowNumber(Curschar);
X AppendPositionToUndobuff(Curschar->index, nn);
X AppendPositionToUndoUndobuff(Curschar->index, nn);
X
X while (Prenum > 0) {
X AppendToRedobuff("r");
X AppendToRedobuff(mkstr(nchar));
X
X AppendToUndobuff("r");
X AppendToUndobuff(mkstr(gchar(Curschar)));
X
X AppendToUndoUndobuff("r");
X AppendToUndoUndobuff(mkstr(nchar));
X
X pchar(Curschar, nchar); /* Change current character. */
X
X if (Prenum > 1) {
X oneright();
X AppendToRedobuff("l");
X AppendToUndobuff("l");
X AppendToUndoUndobuff("l");
X }
X Prenum--;
X }
X
X CHANGED;
X S_LINE_NOT_VALID;
X break;
X
X case '~': /* swap case */
X CLEAROP;
X if (lineempty(Curschar)) {
X beep();
X break;
X }
X ResetBuffers();
X
X n = RowNumber(Curschar);
X AppendPositionToUndobuff(Curschar->index, n);
X AppendPositionToUndoUndobuff(Curschar->index, n);
X
X Prenum = DEFAULT1(Prenum);
X if (Prenum > 0) {
X AppendNumberToRedobuff(Prenum);
X AppendNumberToUndobuff(Prenum);
X AppendNumberToUndoUndobuff(Prenum);
X }
X AppendToRedobuff("~");
X AppendToUndobuff("~");
X AppendToUndoUndobuff("~");
X
X while (Prenum > 0) {
X c = gchar(Curschar);
X if (isalpha(c)) {
X if (islower(c))
X pchar(Curschar, toupper(c));
X else
X pchar(Curschar, tolower(c));
X }
X if (!oneright())
X break;
X Prenum--;
X }
X
X CHANGED;
X S_LINE_NOT_VALID;
X break;
X
X case UNDO_SHIFTJ:
X CLEAROP;
X if (UndoInProgress) {
X (void) dojoin(FALSE, FALSE);
X break;
X }
X goto doSHIFTJcommand;
X
X case 'J':
X CLEAROP;
XdoSHIFTJcommand:
X if (nextline(Curschar) == NULL) { /* on last line */
X beep();
X break;
X }
X ResetBuffers();
X
X temp_Curschar = *Curschar;
X nn = strlen(Curschar->linep->s);
X if (nn < 0)
X nn = 0;
X n = RowNumber(&temp_Curschar);
X
X AppendToRedobuff("J");
X
X AppendPositionToUndobuff(nn, n);
X
X AppendPositionToUndoUndobuff(0, n);
X AppendToUndoUndobuff("J");
X
X if (linewhite(nextline(Curschar))) {
X AppendToUndobuff("a\n");
X if (!dojoin(FALSE, TRUE)) {
X beep();
X break;
X }
X } else if (lineempty(Curschar)) {
X AppendToUndobuff("i\n");
X if (!dojoin(FALSE, TRUE)) {
X beep();
X break;
X }
X } else {
X AppendToUndobuff("dli\n");
X if (!dojoin(TRUE, TRUE)) {
X beep();
X break;
X }
X }
X
X AppendToUndobuff(ESC_STR);
X AppendPositionToUndobuff(nn, n);
X break;
X
X case K_CGRAVE: /* shorthand command */
X CLEAROP;
X stuffReadbuff(":e #\n");
X break;
X
X case 'Z': /* write, if changed, and exit */
X if (vgetc() != 'Z') {
X beep();
X break;
X }
X if (Changed) {
X if (Filename != NULL) {
X if (!writeit(Filename, (LPtr *) NULL, (LPtr *) NULL))
X return;
X } else {
X emsg("No output file");
X return;
X }
X }
X getout(0);
X break;
X
X case '.':
X CLEAROP;
X if (Redobuffptr != NULL) {
X stuffReadbuff(Redobuff);
X
X stuffReadbuff(ENABLE_REDRAWING_STR);
X RedrawingDisabled = TRUE;
X } else
X beep();
X break;
X
X case 'u':
X case K_UNDO:
X CLEAROP;
X if (UndoInProgress) {
X p = UndoUndobuff;
X UndoUndobuff = Undobuff;
X Undobuff = p;
X p = UndoUndobuffptr;
X UndoUndobuffptr = Undobuffptr;
X Undobuffptr = p;
X
X UndoInProgress = FALSE;
X RedrawingDisabled = FALSE;
X S_NOT_VALID;
X } else if (Undobuffptr != NULL) {
X stuffReadbuff(Undobuff);
X stuffReadbuff("u");
X UndoInProgress = TRUE;
X RedrawingDisabled = TRUE;
X } else {
X beep();
X }
X break;
X
X default:
X CLEAROP;
X beep();
X break;
X }
X
X /*
X * If an operation is pending, handle it...
X */
X if (finish_op) { /* we just finished an operator */
X if (operator == NOP) /* ... but it was cancelled */
X return;
X
X switch (operator) {
X
X case LSHIFT:
X case RSHIFT:
X ResetBuffers();
X
X n = RowNumber(&startop);
X AppendPositionToUndobuff(startop.index, n);
X AppendPositionToUndoUndobuff(startop.index, n);
X if (Prenum != 0) {
X AppendNumberToRedobuff(Prenum);
X AppendNumberToUndobuff(Prenum);
X AppendNumberToUndoUndobuff(Prenum);
X }
X AppendToRedobuff((operator == LSHIFT) ? "<" : ">");
X AppendToUndobuff((operator == LSHIFT) ? ">" : "<");
X AppendToUndoUndobuff((operator == LSHIFT) ? "<" : ">");
X AppendToRedobuff(mkstr(c));
X if (c == '>')
X AppendToUndobuff("<");
X else if (c == '<')
X AppendToUndobuff(">");
X else
X AppendToUndobuff(mkstr(c));
X AppendToUndoUndobuff(mkstr(c));
X
X doshift(operator);
X break;
X
X case DELETE:
X ResetBuffers();
X
X n = RowNumber(&startop);
X AppendPositionToUndoUndobuff(startop.index, n);
X
X temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
X n = RowNumber(&temp_Curschar);
X if (Prenum != 0) {
X AppendNumberToRedobuff(Prenum);
X AppendNumberToUndoUndobuff(Prenum);
X }
X AppendToRedobuff("d");
X AppendToUndoUndobuff("d");
X AppendToRedobuff(mkstr(c));
X AppendToUndoUndobuff(mkstr(c));
X if (nchar != NUL) {
X AppendToRedobuff(mkstr(nchar));
X AppendToUndoUndobuff(mkstr(nchar));
X }
X AppendPositionToUndobuff(temp_Curschar.index, n);
X
X dodelete(!UndoInProgress, !UndoInProgress, !UndoInProgress);
X
X AppendPositionToUndobuff(temp_Curschar.index, n);
X break;
X
X case YANK:
X ResetBuffers(); /* no redo/undo/(undo of undo) on yank... */
X if (!doyank())
X msg("yank buffer exceeded");
X if (!ybcrossline)
X *Curschar = startop;
X else if (lt(&startop, Curschar))
X *Curschar = startop;
X break;
X
X case CHANGE:
X ResetBuffers();
X
X n = RowNumber(&startop);
X AppendPositionToUndoUndobuff(startop.index, n);
X
X temp_Curschar = (lt(&startop, Curschar) ? startop : *Curschar);
X n = RowNumber(&temp_Curschar);
X if (mtype == MLINE)
X AppendPositionToUndobuff(0, n);
X else
X AppendPositionToUndobuff(temp_Curschar.index, n);
X
X if (Prenum != 0) {
X AppendNumberToRedobuff(Prenum);
X AppendNumberToUndoUndobuff(Prenum);
X }
X AppendToRedobuff("c");
X AppendToUndoUndobuff("c");
X AppendToRedobuff(mkstr(c));
X AppendToUndoUndobuff(mkstr(c));
X if (nchar != NUL) {
X AppendToRedobuff(mkstr(nchar));
X AppendToUndoUndobuff(mkstr(nchar));
X }
X dochange();
X
X last_command = 'c';
X break;
X
X default:
X beep();
X }
X operator = NOP;
X }
X}
X
X/*
X * tabinout(shift_type, num)
X *
X * If shift_type == RSHIFT, add a tab to the begining of the next num lines;
X * otherwise delete a tab from the beginning of the next num lines.
X */
Xstatic void
Xtabinout(shift_type, num)
X int shift_type;
X int num;
X{
X LPtr *p;
X
X beginline(FALSE);
X while (num-- > 0) {
X beginline(FALSE);
X if (shift_type == RSHIFT)
X inschar(TAB);
X else {
X if (gchar(Curschar) == TAB)
X delchar(TRUE, FALSE);
X }
X if (num > 0) {
X if ((p = nextline(Curschar)) != NULL)
X *Curschar = *p;
X else
X break;
X }
X }
X}
X
X/*
X * doshift - handle a shift operation
X */
Xstatic void
Xdoshift(op)
X int op;
X{
X LPtr top, bot;
X int nlines;
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(top, bot);
X
X nlines = cntllines(&top, &bot);
X *Curschar = top;
X tabinout(op, nlines);
X
X /*
X * The cursor position afterward is the prior of the two positions.
X */
X *Curschar = top;
X
X /*
X * If we were on the last char of a line that got shifted left, then move
X * left one so we aren't beyond the end of the line
X */
X if (gchar(Curschar) == NUL && Curschar->index > 0)
X Curschar->index--;
X
X if (op == RSHIFT)
X oneright();
X else
X oneleft();
X
X S_NOT_VALID;
X
X if (nlines > P(P_RP))
X smsg("%d lines %ced", nlines, (op == RSHIFT) ? '>' : '<');
X}
X
X/*
X * dodelete - handle a delete operation
X */
Xstatic void
Xdodelete(redraw, setup_for_undo, try_to_yank)
X bool_t redraw;
X bool_t setup_for_undo;
X bool_t try_to_yank;
X{
X LPtr top, bot;
X int nlines;
X int n;
X
X /*
X * Do a yank of whatever we're about to delete. If there's too much stuff
X * to fit in the yank buffer, then get a confirmation before doing the
X * delete. This is crude, but simple. And it avoids doing a delete of
X * something we can't put back if we want.
X */
X if (try_to_yank) {
X if (!doyank()) {
X msg("yank buffer exceeded: press <y> to confirm");
X if (vgetc() != 'y') {
X emsg("delete aborted");
X *Curschar = startop;
X return;
X }
X }
X }
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(top, bot);
X
X *Curschar = top;
X nlines = cntllines(&top, &bot);
X
X if (mtype == MLINE) {
X if (operator == CHANGE) {
X last_command_char = 'a';
X delline(nlines - 1);
X Curschar->index = 0;
X while (delchar(TRUE, FALSE));
X } else {
X if ((Filetop->linep->next == top.linep) &&
X (bot.linep->next == Fileend->linep))
X last_command_char = 'a';
X else if (bot.linep->next == Fileend->linep)
X last_command_char = 'o';
X else
X last_command_char = 'O';
X if (setup_for_undo)
X AppendToUndobuff(mkstr(last_command_char));
X delline(nlines);
X }
X } else if (top.linep == bot.linep) { /* del. within line */
X if (!mincl)
X dec(&bot);
X
X if (endofline(&bot))
X last_command_char = 'a';
X else
X last_command_char = 'i';
X if (setup_for_undo)
X AppendToUndobuff(mkstr(last_command_char));
X n = bot.index - top.index + 1;
X while (n--)
X if (!delchar(TRUE, FALSE))
X break;
X } else { /* del. between lines */
X if (endofline(&top)) {
X if (nextline(&top)) {
X if (lineempty(nextline(&top)))
X last_command_char = 'a';
X else
X last_command_char = 'i';
X } else {
X last_command_char = 'a';
X }
X } else {
X last_command_char = 'i';
X }
X if (setup_for_undo)
X AppendToUndobuff(mkstr(last_command_char));
X
X n = Curschar->index;
X while (Curschar->index >= n)
X if (!delchar(TRUE, FALSE))
X break;
X
X top = *Curschar;
X *Curschar = *nextline(Curschar);
X delline(nlines - 2);
X Curschar->index = 0;
X n = bot.index;
X if (!mincl)
X n--;
X
X while (n-- >= 0)
X if (!delchar(TRUE, FALSE))
X break;
X *Curschar = top;
X dojoin(FALSE, FALSE);
X }
X
X if (mtype == MCHAR && nlines == 1 && redraw && P(P_NU) == FALSE) {
X S_LINE_NOT_VALID;
X } else {
X S_NOT_VALID;
X }
X
X if (nlines > P(P_RP))
X smsg("%d fewer lines", nlines);
X
X if (setup_for_undo) {
X AppendToUndobuff(Yankbuff);
X AppendToUndobuff(ESC_STR);
X }
X}
X
X/*
X * dochange - handle a change operation
X */
Xstatic void
Xdochange()
X{
X LPtr l;
X
X if (lt(Curschar, &startop))
X l = *Curschar;
X else
X l = startop;
X
X dodelete(FALSE, FALSE, !UndoInProgress);
X
X if ((l.index > Curschar->index) && !lineempty(Curschar))
X inc(Curschar);
X
X startinsert(FALSE);
X}
X
Xstatic bool_t
Xdoyank()
X{
X LPtr top, bot;
X char *ybend = &Yankbuff[YANKSIZE - 1];
X int nlines;
X
X Yankbuffptr = Yankbuff;
X
X top = startop;
X bot = *Curschar;
X
X if (lt(&bot, &top))
X pswap(top, bot);
X
X nlines = cntllines(&top, &bot);
X
X ybtype = mtype; /* set the yank buffer type */
X ybcrossline = FALSE;
X if (LINEOF(&top) != LINEOF(&bot))
X ybcrossline = TRUE;
X
X if (mtype == MLINE) {
X ybcrossline = TRUE;
X top.index = 0;
X bot.index = strlen(bot.linep->s);
X /*
X * The following statement checks for the special case of yanking a
X * blank line at the beginning of the file. If not handled right, we
X * yank an extra char (a newline).
X */
X if (dec(&bot) == -1) {
X *Yankbuff = NUL;
X Yankbuffptr = NULL;
X return TRUE;
X }
X } else {
X if (!mincl)
X if (!equal(&top, &bot))
X dec(&bot);
X }
X
X for (; ltoreq(&top, &bot); inc(&top)) {
X *Yankbuffptr = (gchar(&top) != NUL) ? gchar(&top) : NL;
X Yankbuffptr++;
X if (Yankbuffptr >= ybend) {
X *Yankbuffptr = NUL;
X msg("yank too big for buffer");
X ybtype = MBAD;
X return FALSE;
X }
X }
X
X *Yankbuffptr = NUL;
X
X if (operator == YANK)
X if (nlines > P(P_RP))
X smsg("%d lines yanked", nlines);
X
X return TRUE;
X}
X
Xstatic void
Xdoput(dir)
X int dir;
X{
X bool_t type;
X
X if (ybtype == MBAD) {
X beep();
X return;
X }
X type = (ybtype == MCHAR);
X if (dir == FORWARD)
X stuffReadbuff(type ? "a" : "o");
X else
X stuffReadbuff(type ? "i" : "O");
X
X stuffReadbuff(Yankbuff);
X stuffReadbuff(ESC_STR);
X
X if (ybtype != MCHAR)
X stuffReadbuff("^");
X}
X
Xstatic void
Xstartinsert(startln)
X int startln; /* if set, insert at start of line */
X{
X *Insstart = *Curschar;
X if (startln) {
X Insstart->index = 0;
X }
X *Insbuff = NUL;
X Insbuffptr = NULL;
X
X State = INSERT;
X if (P(P_MO))
X msg("Insert Mode");
X}
X
Xvoid
XResetBuffers()
X{
X if (UndoInProgress)
X return;
X
X *Redobuff = NUL;
X Redobuffptr = NULL;
X
X *Undobuff = NUL;
X Undobuffptr = NULL;
X
X *UndoUndobuff = NUL;
X UndoUndobuffptr = NULL;
X}
X
Xvoid
XAppendToInsbuff(s)
X char *s;
X{
X if (UndoInProgress)
X return;
X
X if (Insbuffptr == NULL) {
X if ((strlen(s) + 1) < INSERT_SIZE) {
X strcpy(Insbuff, s);
X Insbuffptr = Insbuff;
X return;
X }
X } else if ((strlen(Insbuff) + strlen(s) + 1) < INSERT_SIZE) {
X strcat(Insbuff, s);
X return;
X }
X emsg("Couldn't AppendToInsbuff() - clearing Insbuff\n");
X *Insbuff = NUL;
X Insbuffptr = NULL;
X}
X
Xvoid
XAppendToRedobuff(s)
X char *s;
X{
X if (UndoInProgress)
X return;
X
X if (Redobuffptr == (char *) (-2)) {
X return;
X }
X if (Redobuffptr == (char *) (-1)) {
X Redobuffptr = (char *) (-2);
X emsg("Couldn't AppendToRedobuff() - Redobuff corrupt");
X return;
X }
X if (Redobuffptr == NULL) {
X if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcpy(Redobuff, s);
X Redobuffptr = Redobuff;
X return;
X }
X } else if ((strlen(Redobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcat(Redobuff, s);
X return;
X }
X emsg("Couldn't AppendToRedobuff() - clearing Redobuff");
X *Redobuff = NUL;
X Redobuffptr = (char *) (-1);
X}
X
Xvoid
XAppendNumberToRedobuff(n)
X int n;
X{
X char buf[32];
X
X if (UndoInProgress)
X return;
X
X sprintf(buf, "%d", n);
X AppendToRedobuff(buf);
X}
X
Xvoid
XAppendToUndobuff(s)
X char *s;
X{
X if (UndoInProgress)
X return;
X
X if (Undobuffptr == (char *) (-2)) {
X return;
X }
X if (Undobuffptr == (char *) (-1)) {
X Undobuffptr = (char *) (-2);
X emsg("Couldn't AppendToUndobuff() - Undobuff corrupt");
X return;
X }
X if (Undobuffptr == NULL) {
X if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcpy(Undobuff, s);
X Undobuffptr = Undobuff;
X return;
X }
X } else if ((strlen(Undobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcat(Undobuff, s);
X return;
X }
X emsg("Couldn't AppendToUndobuff() - clearing Undobuff");
X *Undobuff = NUL;
X Undobuffptr = (char *) (-1);
X}
X
Xvoid
XAppendNumberToUndobuff(n)
X int n;
X{
X char buf[32];
X
X if (UndoInProgress)
X return;
X
X sprintf(buf, "%d", n);
X AppendToUndobuff(buf);
X}
X
Xvoid
XAppendPositionToUndobuff(column, row)
X int column;
X int row;
X{
X if (UndoInProgress)
X return;
X
X AppendNumberToUndobuff(row);
X AppendToUndobuff("G");
X AppendNumberToUndobuff(column);
X if (column)
X AppendToUndobuff("l");
X}
X
Xvoid
XAppendToUndoUndobuff(s)
X char *s;
X{
X if (UndoInProgress)
X return;
X
X if (UndoUndobuffptr == (char *) (-2)) {
X return;
X }
X if (UndoUndobuffptr == (char *) (-1)) {
X UndoUndobuffptr = (char *) (-2);
X emsg("Couldn't AppendToUndoUndobuff() - UndoUndobuff corrupt");
X return;
X }
X if (UndoUndobuffptr == NULL) {
X if ((strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcpy(UndoUndobuff, s);
X UndoUndobuffptr = Undobuff;
X return;
X }
X } else if ((strlen(UndoUndobuff) + strlen(s) + 1) < REDO_UNDO_SIZE) {
X strcat(UndoUndobuff, s);
X return;
X }
X emsg("Couldn't AppendToUndoUndobuff() - clearing UndoUndobuff");
X *UndoUndobuff = NUL;
X UndoUndobuffptr = (char *) (-1);
X}
X
Xvoid
XAppendNumberToUndoUndobuff(n)
X int n;
X{
X char buf[32];
X
X if (UndoInProgress)
X return;
X
X sprintf(buf, "%d", n);
X AppendToUndoUndobuff(buf);
X}
X
Xvoid
XAppendPositionToUndoUndobuff(column, row)
X int column;
X int row;
X{
X if (UndoInProgress)
X return;
X
X AppendNumberToUndoUndobuff(row);
X AppendToUndoUndobuff("G");
X AppendNumberToUndoUndobuff(column);
X if (column)
X AppendToUndoUndobuff("l");
X}
X
Xstatic bool_t
Xdojoin(leading_space, strip_leading_spaces)
X bool_t leading_space;
X bool_t strip_leading_spaces;
X{
X int scol; /* save cursor column */
X int currsize; /* size of the current line */
X int nextsize; /* size of the next line */
X
X if (nextline(Curschar) == NULL) /* on last line */
X return FALSE;
X
X nextsize = strlen(Curschar->linep->next->s);
X if (!canincrease(nextsize))
X return FALSE;
X
X currsize = strlen(Curschar->linep->s);
X
X while (oneright()); /* to end of line */
X
X strcat(Curschar->linep->s, Curschar->linep->next->s);
X
X /*
X * Delete the following line. To do this we move the cursor there
X * briefly, and then move it back. Don't back up if the delete made us
X * the last line.
X */
X Curschar->linep = Curschar->linep->next;
X scol = Curschar->index;
X
X if (nextline(Curschar) != NULL) {
X delline(1);
X Curschar->linep = Curschar->linep->prev;
X } else
X delline(1);
X
X Curschar->index = scol;
X
X if (currsize)
X oneright(); /* go to first char. of joined line */
X
X if (nextsize != 0 && strip_leading_spaces) {
X /*
X * Delete leading white space on the joined line and insert a single
X * space.
X */
X while (gchar(Curschar) == ' ' || gchar(Curschar) == TAB) {
X delchar(TRUE, TRUE);
X }
X if (leading_space)
X inschar(' ');
X }
X CHANGED;
X
X return TRUE;
X}
X
X/*
X * linewhite() - returns TRUE if the line consists only of white space
X */
X
Xbool_t
Xlinewhite(p)
X LPtr *p;
X{
X register int i;
X register char c;
X
X i = 1;
X c = p->linep->s[0];
X while (c != NUL) {
X if (c != ' ' && c != '\t')
X return (FALSE);
X c = p->linep->s[i++];
X }
X
X return (TRUE);
X}
SHAR_EOF
echo "End of archive 3 (of 6)"
# if you want to concatenate archives, remove anything after this line
exit